package com.icw.utility.query;

import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import org.springframework.beans.BeanUtils;

import com.icw.utility.IcwUtils;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;

@NoArgsConstructor
@AllArgsConstructor
public class IcwCriterion {

	public IcwCriterion(String op, String property, Object value) {
		this.op = op;
		this.property = property;
		this.value = value;
	}

	public IcwCriterion(String op, IcwCriterion... criterions) {
		this.op = op;
		this.criterions = criterions;
	}

	public String op;

	public String property;

	@Setter
	private Object value;

	public Object getValue() {
		try {
			String fixprop = fixprop(this.property);
			if (true// e
					&& this.property != null // e
					&& this.value != null// e
					&& fieldClassMap.containsKey(fixprop))// e
			{
				Class<?> clazz = fieldClassMap.get(fixprop);
				if ((this.value instanceof String || this.value instanceof Number) && Date.class.isAssignableFrom(clazz)) {
					if (this.value instanceof String) {
						String stringValue = (String) value;
						if (stringValue.length() == 10) {
							return IcwUtils.dateFormat("yyyy-MM-dd").parse((String) this.value);
						} else if (stringValue.length() == 19) {
							return IcwUtils.dateFormat().parse((String) this.value);
						} else {
							return this.value;
						}
					} else if (this.value instanceof Number) {
						Number numberValue = (Number) value;
						return new Date(numberValue.longValue());
					} else {
						return this.value;
					}
				} else if (BigDecimal.class.isAssignableFrom(clazz)) {
					if (String.class.isInstance(value)) return new BigDecimal((String) this.value);
					else if (Number.class.isInstance(value)) return new BigDecimal(((Number) value).doubleValue());
					else return this.value;
				} else {
					return this.value;
				}
			} else {
				return this.value;
			}
		} catch (Exception e) {
			return this.value;
		}
	}

	private String fixprop(String property2) {
		if (property2 == null) {
			return null;
		} else {
			int index = property2.lastIndexOf(".");
			if (index >= 0) {
				return property2.substring(index + 1);
			} else {
				return property2;
			}
		}
	}

	public IcwCriterion[] criterions;

	private static final Map<String, Class<?>> fieldClassMap = new HashMap<>();
	static {
		IcwUtils.tryCatch(() -> {
			Set<Class<?>> classes = IcwUtils.getAllEntities();
			classes.forEach(clazz -> {
				PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(clazz);
				Stream.of(pds).filter(pd -> pd.getWriteMethod() != null).forEach(pd -> {
					Class<?> c = pd.getWriteMethod().getParameterTypes()[0];
					fieldClassMap.put(pd.getName(), c);
				});
			});
		});
	}
}
